<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  
  
  
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <title>
    可重复执行 |
    
    M_W_Q</title>
  
    <link rel="shortcut icon" href="/bolg/favicon.ico">
  
  <link rel="stylesheet" href="/bolg/css/style.css">
  
    <link rel="stylesheet" href="/bolg/fancybox/jquery.fancybox.min.css">
  
  <script src="/bolg/js/pace.min.js"></script>
</head>

<body>
<main class="content">
  <section class="outer">
  

<article id="post-可重复执行" class="article article-type-post" itemscope itemprop="blogPost" data-scroll-reveal>
  
  <div class="article-inner">
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      可重复执行
    </h1>
  
  




      </header>
    

    
      <div class="article-meta">
        <a href="/bolg/2019/10/21/%E5%8F%AF%E9%87%8D%E5%A4%8D%E6%89%A7%E8%A1%8C/" class="article-date">
  <time datetime="2019-10-21T14:06:44.887Z" itemprop="datePublished">2019-10-21</time>
</a>
        
      </div>
    

    
      
    <div class="tocbot"></div>





    

    <div class="article-entry" itemprop="articleBody">
      


      

      
        <h4 id="1-什么是可重复执行"><a href="#1-什么是可重复执行" class="headerlink" title="1.什么是可重复执行"></a>1.什么是可重复执行</h4><p>可重复执行是系统功能服务方在第三方需要调用时可以重复的调用，不会影响系统产生异常数据，导致数据资损而产生一系列的问题进行数据维护（包括防重复，幂等）</p>
<h5 id="防重复"><a href="#防重复" class="headerlink" title="防重复"></a>防重复</h5><p>防重是在防止系统重复执行的系统相同的服务逻辑，基础的理解是该服务在同一个请求下仅仅允许一次执行。</p>
<h5 id="幂等"><a href="#幂等" class="headerlink" title="幂等"></a>幂等</h5><p>幂等（idempotent、idempotence）是一个数学与计算机学概念，常见于抽象代数中。在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数，或幂等方法，是指可以使用相同参数重复执行，并能获得相同结果的函数。这些函数不会影响系统状态，也不用担心重复执行会对系统造成改变。例如，“select()”函数就是一个幂等函数,无论多次执行，其结果都是一样的.更复杂的操作幂等保证是利用唯一交易号(流水号)实现</p>
<h4 id="2-天然幂等无需考虑场景"><a href="#2-天然幂等无需考虑场景" class="headerlink" title="2. 天然幂等无需考虑场景"></a>2. 天然幂等无需考虑场景</h4><ol>
<li>查询操作，不涉及到数据的改动，多次查询都是一样的</li>
<li>删除操作，删除数据使用唯一号，而且后续不会再次使用的唯一号能保证唯一幂等</li>
</ol>
<h4 id="3-考虑时机"><a href="#3-考虑时机" class="headerlink" title="3. 考虑时机"></a>3. 考虑时机</h4><p>下面的的情况一般是应用于会影响到数据的系统服务</p>
<ol>
<li>其它系统服务调用（rpc，rest等方式）：现在微服务的架构特点，服务拆分和架构上的功能服务拆分导致我们必须是有rpc，rest或者mq的方式来进行系统间的交互。</li>
<li>批处理任务调度异常（重复调用）：调度任务系统出现异常，导致已经调用过的任务再次发起需要我们对其进行场景考虑</li>
<li>批处理任务同时唤醒多台机器执行同一个任务：批处理任务配置时同时唤醒多台机器进行数据数据处理，这就需要N台机器获取数据要执行的数据需要进行区分，防止多台机器对同一个数据进行修改，导致数据异常，这个时候就需要考虑到调度任务唤起，任务获取和执行这个三个方面来进行解决问题不同的问题具体对待</li>
<li>批处理断点续起问题：任务时间太久导致任务执行一半失败，一种方式是回滚前面已执行数据，而是对已执行的进行标记对未执行的继续执行，在大量任务中，我们会更加偏向第二种方式。</li>
</ol>
<h4 id="4-解决方案中需要了解的知识"><a href="#4-解决方案中需要了解的知识" class="headerlink" title="4. 解决方案中需要了解的知识"></a>4. 解决方案中需要了解的知识</h4><ol>
<li>悲观锁<br>悲观锁是对事情保持悲观的态度，认为会产生别人进行修改数据，有冲突操作，每次进行执行的时候就进行加锁不允许其它的进行操作.有数据库方面的表锁，行数，java里面的<a href="https://www.jianshu.com/p/7c7a5df5bda6" target="_blank" rel="noopener">闭锁</a>，<a href="https://www.jianshu.com/p/86c720945fdc" target="_blank" rel="noopener">栅栏</a>，<a href="https://www.jianshu.com/p/0524191dcf76" target="_blank" rel="noopener">信号量</a>，<a href="https://blog.csdn.net/tongdanping/article/details/79647337" target="_blank" rel="noopener">synchronized</a>，ReentrantLock都是悲观锁的典型设计<ul>
<li>数据库：我们的行锁，表锁都是悲观锁</li>
<li>redis分布式锁：目前使用的也是悲观锁的概念</li>
</ul>
</li>
<li>乐观锁<br>乐观锁假设认为数据一般情况下不会造成冲突，所以在数据进行提交更新的时候，才会正式对数据的冲突与否进行检测，如果发现冲突了，则让返回用户错误的信息，让用户决定如何去做或者使用系统策略（状态机和CAS）<ul>
<li>状态机：状态机一般是指定一个状态来进行标识，应用级别一般是单应用防止并发，数据库级别可以是用来做分布式控制</li>
<li>CAS：有三个操作数据，A(预期值)，V(内存里面当前值)，B(修改值)：只有A和V数据相同时才会将V值修改为B，否则不进行任何操作。是并发情况下保证数据的正常性的一种方案。</li>
</ul>
</li>
<li>去重表<br>去重表指的利用数据库创建一个表，利用数据库唯一索引来保证每一个条数据都是不一样的，通过策略保证数据不会重复执行和执行结果幂等</li>
<li>token唯一防重复<br>token是类似于唯一标识<a href="https://jwt.io/" target="_blank" rel="noopener">JTW</a>（java Token Web）经常用于<a href="https://oauth.net/2/" target="_blank" rel="noopener">OAuth2</a>等场景。token在幂等方面的贡献只是它的唯一性，我们进行选择的时候主要的是根据业务场景确定为唯一值，也可以是随机生成的只要保证它的唯一性，保证在做幂等号的时候不会出现问题。</li>
</ol>
<h4 id="5-两种具体处理情况"><a href="#5-两种具体处理情况" class="headerlink" title="5. 两种具体处理情况"></a>5. 两种具体处理情况</h4><ol>
<li>拒绝策略（重复的请求过来进行忽略处理，主要的场景是调用方不需要返回结果）</li>
<li>相同响应策略（重复的请求过来进行上一次结果的返回）</li>
</ol>
<h4 id="6-执行方案"><a href="#6-执行方案" class="headerlink" title="6. 执行方案"></a>6. 执行方案</h4><table>
<thead>
<tr>
<th>场景示例</th>
<th>策略</th>
<th>解决方案</th>
</tr>
</thead>
<tbody><tr>
<td>其它系统调用</td>
<td>相同响应策略</td>
<td>解决方案一,解决方案二</td>
</tr>
<tr>
<td>批处理任务调度异常，重复调用</td>
<td>拒绝策略</td>
<td>解决方案一,解决方案二</td>
</tr>
<tr>
<td>批处理任务同时唤醒多台机器执行同一个任务</td>
<td>拒绝策略</td>
<td>解决方案三</td>
</tr>
<tr>
<td>批处理断点续起问题</td>
<td>相同响应策略</td>
<td>解决方案一,解决方案二</td>
</tr>
</tbody></table>
<h5 id="方案一"><a href="#方案一" class="headerlink" title="方案一"></a>方案一</h5><p>依赖数据库方式<br><img src="evernotecid://77FB468C-3E88-43B1-A06D-88D14FB04A37/appyinxiangcom/8577930/ENResource/p208" alt="5800a93fa76068620d664c8b9ef2cb97.png"></p>
<h5 id="方案二"><a href="#方案二" class="headerlink" title="方案二"></a>方案二</h5><p>依赖redis, 其它系统调用的情况下，系统异常重试：（调用系统提供唯一请求ID)<br><img src="evernotecid://77FB468C-3E88-43B1-A06D-88D14FB04A37/appyinxiangcom/8577930/ENResource/p209" alt="9738b91e71d108a156abd62e8b8afb7b.png"></p>
<h5 id="方案三"><a href="#方案三" class="headerlink" title="方案三"></a>方案三</h5><p>主要是依赖于数据库状态字段来对数据是否处理进行标识提高可靠性<br><img src="evernotecid://77FB468C-3E88-43B1-A06D-88D14FB04A37/appyinxiangcom/8577930/ENResource/p207" alt="4bb95b6ed82d2c7ca8e1ba8fbaa29363.png"></p>
<ul>
<li>不断的加锁是会对性能造成影响的。而且增加程序的复杂性，所以我们在操作的时候是需要对程序进行充分的评估来确定加锁时间，加多少锁和使用什么样的锁</li>
<li>执行批处理的任务是可以进行优化，主要是针对获取数据锁，每个数据获取表里面都是有主键或者是包含业务性的字段，我们可以通过最简单的hash分块将其分成多个粒度，类似于1.7版本的ConcurrentHashMap的分段锁的实现方式</li>
</ul>
<p>PS: 上面所有的锁都是需要有一个超时时间设置，防止程序异常导致所有业务卡死在一个节点里面。</p>
<h4 id="7-决策树"><a href="#7-决策树" class="headerlink" title="7. 决策树"></a>7. 决策树</h4><p><a href="http://naotu.baidu.com/file/6850eb6c113d71bd7726e53029c67e73?token=2fa297e97609986f" target="_blank" rel="noopener">决策树引导</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://m_aleen.gitee.io/bolg/2019/10/21/%E5%8F%AF%E9%87%8D%E5%A4%8D%E6%89%A7%E8%A1%8C/" data-id="ck32z8ytt000669dbeumm7ggu"
         class="article-share-link">Share</a>
      
    </footer>

  </div>

  
    
  <nav class="article-nav">
    
      <a href="/bolg/2019/10/21/Hexo+github%E6%90%AD%E5%BB%BA%E8%87%AA%E5%B7%B1%E7%9A%84%E4%B8%93%E5%B1%9E%E5%8D%9A%E5%AE%A2/" class="article-nav-link">
        <strong class="article-nav-caption">Newer posts</strong>
        <div class="article-nav-title">
          
            Hexo+github搭建自己的专属博客
          
        </div>
      </a>
    
    
      <a href="/bolg/2019/10/21/Effective%20Java%20%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0%EF%BC%88%E4%B9%8B%E5%88%9B%E5%BB%BA%E5%92%8C%E9%94%80%E6%AF%81%E5%AF%B9%E8%B1%A1%EF%BC%89/" class="article-nav-link">
        <strong class="article-nav-caption">Olde posts</strong>
        <div class="article-nav-title">Effective Java 阅读笔记（之创建和销毁对象）</div>
      </a>
    
  </nav>


  

  
    
  

</article>



</section>
  <footer class="footer">
  <div class="outer">
    <div class="float-right">
      <ul class="list-inline">
  
    <li><i class="fe fe-smile-alt"></i> <span id="busuanzi_value_site_uv"></span></li>
  
    <li><i class="fe fe-bookmark"></i> <span id="busuanzi_value_page_pv"></span></li>
  
</ul>
    </div>
    <ul class="list-inline">
      <li>&copy; 2019 M_W_Q</li>
      <li>Powered by <a href="http://hexo.io/" target="_blank">Hexo</a></li>
      <li>Theme  <a href="https://github.com/zhwangart/hexo-theme-ocean" target="_blank" rel="noopener">Ocean</a></li>
    </ul>
  </div>
</footer>

</main>

<aside class="sidebar sidebar-specter">
  
    <button class="navbar-toggle"></button>
<nav class="navbar">
  
    <div class="logo">
      <a href="/bolg/"><img src="/bolg/images/hexo.svg" alt="M_W_Q"></a>
    </div>
  
  <ul class="nav nav-main">
    
      <li class="nav-item">
        <a class="nav-item-link" href="/bolg/">Home</a>
      </li>
    
      <li class="nav-item">
        <a class="nav-item-link" href="/bolg/archives">Archives</a>
      </li>
    
      <li class="nav-item">
        <a class="nav-item-link" href="/bolg/gallery">Gallery</a>
      </li>
    
      <li class="nav-item">
        <a class="nav-item-link" href="/bolg/about">About</a>
      </li>
    
    <li class="nav-item">
      <a class="nav-item-link nav-item-search" title="搜索">
        <i class="fe fe-search"></i>
        Search
      </a>
    </li>
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      <div class="totop" id="totop">
  <i class="fe fe-rocket"></i>
</div>
    </li>
    <li class="nav-item">
      
        <a class="nav-item-link" target="_blank" href="/bolg/atom.xml" title="RSS Feed">
          <i class="fe fe-feed"></i>
        </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
  </aside>
  <script src="/bolg/js/jquery-2.0.3.min.js"></script>
<script src="/bolg/js/jquery.justifiedGallery.min.js"></script>
<script src="/bolg/js/lazyload.min.js"></script>
<script src="/bolg/js/busuanzi-2.3.pure.min.js"></script>

  <script src="/bolg/fancybox/jquery.fancybox.min.js"></script>



  <script src="/bolg/js/tocbot.min.js"></script>
  <script>
    // Tocbot_v4.7.0  http://tscanlin.github.io/tocbot/
    tocbot.init({
      tocSelector: '.tocbot',
      contentSelector: '.article-entry',
      headingSelector: 'h1, h2, h3, h4, h5, h6',
      hasInnerContainers: true,
      scrollSmooth: true,
      positionFixedSelector: '.tocbot',
      positionFixedClass: 'is-position-fixed',
      fixedSidebarOffset: 'auto',
    });
  </script>


<script src="/bolg/js/ocean.js"></script>

</body>
</html>